/*
 * ecc.h
 *
 *  Created on: Oct 2, 2015
 *      Author: tslld
 */

#ifndef INC_ECC_H_
#define INC_ECC_H_

#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#include<gmp.h>
#include<assert.h>
#include<string.h> /* memset */
#include<unistd.h> /* close */
#include<time.h>

#ifndef uchar
#define uchar unsigned char // 8-bit byte
#endif

#ifndef uint
#define uint unsigned int // 32-bit word
#endif

#ifndef uint64
typedef unsigned long long uint64;
#endif


// ROTL32 performs a left rotate for an 32-bit integer
#ifndef ROTL32
#define ROTL32(a,b) (((a) << (b)) | ((a) >> (32-(b))))
#endif

// ROTR32 performs a right rotate for an 32-bit integer
#ifndef ROTR32
#define ROTR32(a,b) (((a) >> (b)) | ((a) << (32-(b))))
#endif

// ROTL64 performs a left rotate for an 64-bit integer
#ifndef ROTL64
#define ROTL64(a,b) (((a) << (b)) | ((a) >> (64-(b))))
#endif

// ROTR64 performs a right rotate for an 64-bit integer
#ifndef ROTR64
#define ROTR64(a,b) (((a) >> (b)) | ((a) << (64-(b))))
#endif

// SHFR shifts the integer a in the right b bits
#ifndef SHFR
#define SHFR(a,b) ((a) >> (b))
#endif

// SHFR shifts the integer a in the left b bits
#ifndef SHFL
#define SHFL(a,b) ((a) << (b))
#endif

#ifndef CH
#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
#endif

#ifndef MAJ
#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
#endif

#ifndef LIKELY
#define LIKELY(x) __builtin_expect(!!(x), 1)
#endif

#ifndef UNLIKELY
#define UNLIKELY(x) __builtin_expect(!!(x), 0)
#endif

/*
 * Define structure of a curve point in projective coordinates
 * Z = 1 when points represented in affine coordinates
 */
typedef struct ec_point_proj_st* ec_point_proj;

struct ec_point_proj_st{
	mpz_t X;
	mpz_t Y;
	mpz_t Z;				/* Three Jacobean coordinates.
							 * Given P = (x, y) in affine cooridnates. We have
							 * x = X/Z^2, y = Y/Z^3
							 * The point at infinity (X : Y : Z) = (0 : 1 : 0);
							 */
};


typedef struct ec_point_st* ec_point;

struct ec_point_st{
	mpz_t x; //  two affine coordinates.
	mpz_t y;
	bool infinity;
};

/*
 * Define structure of an elliptic curve E of Weierstrass form: y^2 = x^3 + Ax + B (mod p)
 */

typedef struct ec_group_st* ec_group;

struct ec_group_st {
	char* curve_name;
	mpz_t A, B; /* parameters of the Weierstrass curve */
	mpz_t field; /* prime characteristic of the finite field on which E is defined */
	mpz_t order, cofactor; /* order of the largest subgroup of points and the co-factor of the curve E, that is, #E(Fp) = cofactor * order */
	ec_point generator; /* generator of the largest subgroup of point, G= (Gx, Gy, Gz)s */
};

/*
 * Define structure of a pair of keys: public and private keys generated by group of point group
 */

typedef struct ec_key_st* ec_key;

struct ec_key_st {
    ec_group group;
    ec_point pub_key;
    mpz_t priv_key;
} /* EC_KEY */ ;

/********************************************************************/
/*                      EC_KEY functions                            */
/********************************************************************/

/** Creates a new EC_KEY object.
 *  \return EC_KEY object or NULL if an error occurred.
 */
ec_key ec_key_init(void);
ec_key ec_key_init_set(const ec_group group, const ec_point pubkey, const mpz_t privkey);

/** Creates a new EC_KEY object using a named curve as underlying
 *  EC_GROUP object.
 *  \param  nid  NID of the named curve.
 *  \return EC_KEY object or NULL if an error occurred.
 */
ec_key ec_key_init_by_curve_name(const char* name);

/** Frees a EC_KEY object.
 *  \param  key  EC_KEY object to be freed.
 */

/** Creates a new EC_KEY object and copies the content from src to it.
 *  \param  src  the source EC_KEY object
 *  \return newly created EC_KEY object or NULL if an error occurred.
 */
ec_key ec_key_dup(const ec_key src);

/** Returns the EC_GROUP object of a EC_KEY object
 *  \param  key  EC_KEY object
 *  \return the EC_GROUP object (possibly NULL).
 */

void ec_key_free(ec_key key);

/** Copies a EC_KEY object.
 *  \param  dst  destination EC_KEY object
 *  \param  src  src EC_KEY object
 *  \return dst or NULL if an error occurred.
 */
int ec_key_copy(ec_key dst, const ec_key src);


ec_group ec_key_get_group(const ec_key key);

/** Sets the EC_GROUP of a EC_KEY object.
 *  \param  key    EC_KEY object
 *  \param  group  EC_GROUP to use in the EC_KEY object (note: the EC_KEY
 *                 object will use an own copy of the EC_GROUP).
 *  \return 1 on success and 0 if an error occurred.
 */
int ec_key_set_group(ec_key key, const ec_group group);

/** Returns the private key of a EC_KEY object.
 *  \param  key  EC_KEY object
 *  \return a BIGNUM with the private key (possibly NULL).
 */
void ec_key_get_private_key(mpz_t ret, const ec_key key);

/** Sets the private key of a EC_KEY object.
 *  \param  key  EC_KEY object
 *  \param  prv  BIGNUM with the private key (note: the EC_KEY object
 *               will use an own copy of the BIGNUM).
 *  \return 1 on success and 0 if an error occurred.
 */
void ec_key_set_private_key(ec_key key, const mpz_t prv);

/** Returns the public key of a EC_KEY object.
 *  \param  key  the EC_KEY object
 *  \return a EC_POINT object with the public key (possibly NULL)
 */
ec_point ec_key_get_public_key(const ec_key key);

/** Sets the public key of a EC_KEY object.
 *  \param  key  EC_KEY object
 *  \param  pub  EC_POINT object with the public key (note: the EC_KEY object
 *               will use an own copy of the EC_POINT object).
 *  \return 1 on success and 0 if an error occurred.
 */
int ec_key_set_public_key(ec_key key, const ec_point pub);

/** Creates a new ec private (and optional a new public) key.
 *  \param  key  	EC_KEY object
 *  \param 	genpub	0 generate private key; 1 generate public key
 *  \return 1 on success and 0 if an error occurred.
 */
int ec_key_generate_key(ec_key key, int genpub);

/** Verifies that a private and/or public key is valid.
 *  \param  key  the EC_KEY object
 *  \return 1 on success and 0 otherwise.
 */
int ec_key_check_key(const ec_key key);

int ec_key_check_public_key(ec_point Q, ec_group group);

/** Creates a table of pre-computed multiples of the generator to
 *  accelerate further EC_KEY operations.
 *  \param  key  EC_KEY object
 *  \return 1 on success and 0 if an error occurred.
 */
int ec_key_precompute_mult(ec_key key);

/** Prints out the contents of a EC_KEY object
 *  \param  fp   file descriptor to which the information is printed
 *  \param  key  EC_KEY object
 */
void ec_key_print_fp(FILE *fp, const ec_key key);


/*
typedef enum curves curve_list;

enum curves{
	secp224k1,
	secp224r1, // curve nist224
	secp256k1,
	secp256r1
};*/

typedef struct ecdsa_sig_st* ecdsa_sig;

struct ecdsa_sig_st {
    mpz_t r;
    mpz_t s;
};


/********************************************************************/
/* 						ECDSA functions								*/
/********************************************************************/
/** Allocates and initialize a ecdsa_sig structure
 *  \return pointer to a ecdsa_sig structure or NULL if an error occurred
 */
ecdsa_sig ecs_init();

ecdsa_sig ecs_init_set(mpz_t R, mpz_t S);

/** frees a ECDSA_SIG structure
 *  \param  sig  pointer to the ECDSA_SIG structure
 */
void ecs_free(ecdsa_sig sig);

/** Get/Set the value r of the signature
 * 	\param P	pointer to an ec_point structure
 * 	\param X	BIG number, field characteristic
 * 								required to be initialized
 * 	\return		X-coordinate of P
 */
void ecs_get_r(ecdsa_sig sig, mpz_t R);
void ecs_set_r(ecdsa_sig sig, mpz_t R);

/** Get/Set the value r of the signature
 * 	\param P	pointer to an ec_point structure
 * 	\param X	BIG number, field characteristic
 * 								required to be initialized
 * 	\return		X-coordinate of P
 */
void ecs_get_s(ecdsa_sig sig, mpz_t S);
void ecs_set_s(ecdsa_sig sig, mpz_t S);

int ecs_cmp(ecdsa_sig S1, ecdsa_sig S2);
int ecs_cpy(ecdsa_sig dest, ecdsa_sig src);
ecdsa_sig ecs_dup(ecdsa_sig src);

/** Print out the content (r, s) of a ecdsa_sig structure
 *  \param	sig pointer to the ecdsa_sig structure
 */
void ecs_print_fp(FILE *fp, ecdsa_sig sig);

/** Precompute parts of the signing operation
 *  \param  eckey  EC_KEY object containing a private EC key
 *  \param  kinv   mpz_t pointer for the inverse of k
 *  \param  rp     mpz_t pointer for x coordinate of k * generator
 *  \return 1 on success and 0 otherwise
 */
int ecdsa_sign_setup(const ec_key eckey, mpz_t kinv, mpz_t rp);

/** Computes the ECDSA signature of the given hash value using
 *  the supplied private key and returns the created signature.
 *  \param  dgst      pointer to the hash value
 *  \param  dgst_len  length of the hash value
 *  \param  kinv     BIGNUM with a pre-computed inverse k (optional)
 *  \param  rp       BIGNUM with a pre-computed rp value (optioanl),
 *  \param  eckey     EC_KEY object containing a private EC key
 *  \return pointer to a ECDSA_SIG structure or NULL if an error occurred
 */
ecdsa_sig ecdsa_sign(const char *dgst, int dgst_len, const mpz_t kinv, const mpz_t rp, const ec_key eckey);

/** Verifies that the given signature is valid ECDSA signature
 *  of the supplied hash value using the specified public key.
 *  \param  dgst     pointer to the hash value
 *  \param  dgstlen  length of the hash value
 *  \param  sig      pointer to the ecdsa_sig structure
 *  \param  eckey    EC_KEY object containing a public EC key
 *  \return 1 if the signature is valid, 0 if the signature is invalid
 *          and -1 on error
 */
int ecdsa_verify(const char *dgst, int dgstlen, const ecdsa_sig sig, ec_group group, ec_point pub_key);




/*Number of curves that can be loaded using domain_parameters_load_curve()*/
#define NUMBER_OF_CURVES (secp256r1 + 1)

/*Default curve, used when no -c/--curve parameter is defined*/
#define DEFAULT_CURVE secp224r1





#endif /* INC_ECC_H_ */
